/*******************************************************************************
 * Copyright (c) 2011-11-10 @author <a href="mailto:iffiff1@hotmail.com">Tyler Chen</a>.
 * All rights reserved.
 *
 * Contributors:
 *     <a href="mailto:iffiff1@hotmail.com">Tyler Chen</a> - initial API and implementation
 ******************************************************************************/
package com.redhat.auth.ejb.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.ejb.Remote;
import javax.ejb.Stateless;

import org.springframework.stereotype.Service;

import com.dayatang.domain.InstanceFactory;
import com.dayatang.querychannel.service.QueryChannelService;
import com.dayatang.querychannel.support.Page;
import com.redhat.auth.domain.Account;
import com.redhat.auth.domain.BizSystem;
import com.redhat.auth.domain.BizSystemBinding;
import com.redhat.auth.domain.Role;
import com.redhat.auth.ejb.AccountApplication;
import com.redhat.auth.ejb.vo.AccountVO;
import com.redhat.auth.ejb.vo.BizSystemVO;
import com.redhat.auth.ejb.vo.RoleVO;

/**
 * @author <a href="mailto:iffiff1@hotmail.com">Tyler Chen</a> 
 * @since 2011-11-10
 */
@Service("ramsAccountApplication")
@Stateless(name = "AccountApplicationBean")
@Remote(AccountApplication.class)
@javax.interceptor.Interceptors(SpringEJBIntercepter.class)
public class AccountApplicationImpl implements AccountApplication {

	private static QueryChannelService queryChannel;

	public static QueryChannelService getQueryChannel() {
		if (queryChannel == null) {
			queryChannel = InstanceFactory
					.getInstance(QueryChannelService.class);
		}
		return queryChannel;
	}

	public static void setQueryChannel(QueryChannelService queryChannel) {
		AccountApplicationImpl.queryChannel = queryChannel;
	}

	public void deleteAccount(Long id) {
		Account account = Account.get(id);
		if (account != null) {
			account.remove();
		}
	}

	public AccountVO update(AccountVO vo) {
		Account account = Account.get(vo.getId());
		if (account == null) {
			return null;
		}
		account.setEmail(vo.getEmail());
		account.setRealName(vo.getRealName());
		account.setDescription(vo.getDescription());
		account.update();
		//		try {
		//			UserCacheUtil.removeCacheByUserName(account.getUsername());
		//		} catch (Exception e) {
		//		}
		return toAccountVO(account);
	}

	/**
	 * 根据ID返回一个实体
	 */
	public AccountVO getAccount(long id) {
		return toAccountVO(Account.get(id));
	}

	public boolean changePassword(AccountVO vo) {
		if (vo == null || vo.getId() == null) {
			return false;
		}
		Account account = Account.get(vo.getId());
		if (account == null) {
			return false;
		}
		return account.changePassword(vo.getPassword(), vo.getNewPassword());
	}

	public boolean validatePassword(AccountVO vo) {
		if (vo == null || vo.getId() == null) {
			return false;
		}
		Account account = Account.get(vo.getId());
		if (account == null) {
			return false;
		}
		return account.validatePassword(vo.getPassword());
	}

	/**
	 * 检测同邮件的帐号是否存在
	 */
	public boolean isAccountExistsByEmail(String email) {
		return Account.isEmailExist(email);
	}

	/**
	 * 检测同用户名的帐号是否存在
	 */
	public boolean isAccountExistsByName(String username) {
		return Account.isUsernameExist(username);
	}

	/**
	 * 将一个帐号同多个系统绑定起来
	 * @param accountId  帐号ID
	 * @param systemIds  系统ID
	 * @return
	 */
	public void accountBindSystems(long accountId, String[] systemIds) {
		Account account = Account.get(accountId);
		account.bindingBizSystems(systemIds);
	}

	/**
	 * 将一个帐号同多个系统解除绑定
	 * @param accountId
	 * @param systemIds
	 */
	public void accountUnBindSystem(long accountId, String[] systemIds) {
		Account account = Account.get(accountId);
		account.unBindingBizSystems(systemIds);
	}

	/**
	 * 将一个系统同多个帐号进行绑定
	 * @param systemId
	 * @param accountIds
	 */
	public void systemBindAccount(long systemId, String[] accountIds) {
		BizSystem bizSystem = BizSystem.get(systemId);
		bizSystem.bindingAccounts(accountIds);
	}

	/**
	 * 解除一个系统同多个帐号之间的绑定
	 * @param systemId  要绑定的系统Id
	 * @param accountIds 要绑定的系统
	 */
	public void systemUnBindAccount(long systemId, String[] accountIds) {
		BizSystem bizSystem = BizSystem.get(systemId);
		bizSystem.unBindingAccounts(accountIds);
	}

	/**
	 * 设置一个帐号的绑定的一个系统的状态，可用或不可用
	 */
	public void setBizSystemBindingStatus(long accontId, long systemId,
			int bizSystemBindingStatus) {
		Account account = Account.get(accontId);
		account
				.setSystemStatus(
						systemId,
						BizSystemBinding.Status.ENABLED.ordinal() == bizSystemBindingStatus ? BizSystemBinding.Status.ENABLED
								: BizSystemBinding.Status.DISABLED);
	}

	public AccountVO add(AccountVO vo) {
		Account account = Convertor.vo2po(vo, new Account());
		account.add();
		return toAccountVO(account);
	}

	public void lock(Long accountId) {
		Account account = Account.get(accountId);
		if (account != null) {
			account.disabled();
		}
	}

	public void unLock(Long accountId) {
		Account account = Account.get(accountId);
		if (account != null) {
			account.enabled();
		}
	}

	public AccountVO getAccount(String username) {
		return toAccountVO(Account.get(username));
	}

	public Page<AccountVO> pageQueryAccount(AccountVO vo, int page, int pageSize) {
		List<AccountVO> voList = new ArrayList<AccountVO>();
		String hql = "from Account a where 1=1 ";
		List<Object> params = new ArrayList<Object>();
		String username = vo != null ? vo.getUsername() : null;
		String realName = vo != null ? vo.getRealName() : null;
		if (username != null && (username = username.trim()).length() > 0) {
			hql += "and a.username like ? ";
			params.add("%" + username + "%");
		}
		if (realName != null && (realName = realName.trim()).length() > 0) {
			hql += "and a.realName like ? ";
			params.add("%" + realName + "%");
		}
		{
			hql += "order by a.registryDate desc ";
		}
		Page<Account> pageResult = getQueryChannel().queryPagedResultByPageNo(
				hql, params.toArray(), page, pageSize);
		for (Account a : pageResult.getResult()) {
			voList.add(Convertor.po2vo(a, null));
		}
		return PageUtil.toPage(pageResult, voList);
	}

	/**
	 * 根据一个系统ID联动的查询出相应的Account
	 * @param search
	 * @param page
	 * @param pageSize
	 * @return
	 */
	public List<AccountVO> listAccountBySystemId(AccountVO vo, int page,
			int pageSize) {
		int firstRow = (page - 1) * pageSize;
		List<Account> accounts = new ArrayList<Account>();
		if (vo != null) {
			accounts = getQueryChannel()
					.queryResult(
							"from Account a join a.bizSystemBindings s where a.username like ? and a.realName like ? and  s.bizSystem = "
									+ vo.getId(),
							new Object[] {
									vo.getUsername() == null ? "%" : vo
											.getUsername()
											+ "%",
									vo.getRealName() == null ? "%" : vo
											.getRealName()
											+ "%" }, firstRow, pageSize);
		}
		List<AccountVO> result = new ArrayList<AccountVO>();
		for (Account a : accounts) {
			result.add(Convertor.po2vo(a, null));
		}
		return result;
	}

	/**
	 * 获取一个系统，查询出所有未包含此系统的Account
	 * @param search
	 * @param page
	 * @param pageSize
	 * @return
	 */
	public List<AccountVO> listAccountNotContainsSystemId(AccountVO vo,
			int page, int pageSize) {
		int firstRow = (page - 1) * pageSize;
		List<Account> accounts = new ArrayList<Account>();
		if (vo != null) {
			accounts = getQueryChannel()
					.queryResult(
							"from Account ac where ac.username like ? and ac.realName like ? and ac.id not in (select a.id from Account a join a.bizSystemBindings s where s.bizSystem = "
									+ vo.getId() + ")",
							new Object[] {
									vo.getUsername() == null ? "%" : vo
											.getUsername()
											+ "%",
									vo.getRealName() == null ? "%" : vo
											.getRealName()
											+ "%" }, firstRow, pageSize);
		}
		List<AccountVO> result = new ArrayList<AccountVO>();
		for (Account a : accounts) {
			result.add(Convertor.po2vo(a, null));
		}
		return result;
	}

	/**
	 * 传入accountId时，返回所有此ID未绑定的BizSystem
	 */
	public List<BizSystemVO> listBizSystemNotBindingAccount(AccountVO vo,
			int page, int pageSize) {
		int firstRow = (page - 1) * pageSize;
		List<BizSystem> bizSystems = new ArrayList<BizSystem>();
		List<Long> existsbizSystems = new ArrayList<Long>();

		if (vo != null) {
			Account account = Account.get(vo.getId());

			Set<BizSystemBinding> bizSystemBindings = account
					.getBizSystemBindings();

			for (BizSystemBinding bizSystemBinding : bizSystemBindings) {
				BizSystem bizSystem = bizSystemBinding.getBizSystem();
				existsbizSystems.add(bizSystem.getId());
			}

			if (existsbizSystems.size() == 0) {
				bizSystems = getQueryChannel().queryResult("from BizSystem ",
						new Object[] {}, firstRow, pageSize);
			} else {
				//组装出所有已绑定的systemId
				StringBuffer systemValue = new StringBuffer();
				systemValue.append("(");
				for (int i = 0; i < existsbizSystems.size(); i++) {
					if (i == existsbizSystems.size() - 1) {
						systemValue.append(existsbizSystems.get(i) + ")");
					} else {
						systemValue.append(existsbizSystems.get(i) + ",");
					}
				}

				bizSystems = getQueryChannel().queryResult(
						"from BizSystem s where s.id not in "
								+ systemValue.toString(), new Object[] {},
						firstRow, pageSize);
			}
		}
		List<BizSystemVO> result = new ArrayList<BizSystemVO>();
		for (BizSystem a : bizSystems) {
			result.add(Convertor.po2vo(a, null));
		}
		return result;
	}

	public List<AccountVO> queryAcount(AccountVO vo) {
		List<AccountVO> result = new ArrayList<AccountVO>();
		String hql = "from Account a where 1=1 ";
		List<Object> params = new ArrayList<Object>();
		String username = vo != null ? vo.getUsername() : null;
		String realName = vo != null ? vo.getRealName() : null;
		if (username != null && (username = username.trim()).length() > 0) {
			hql += "and a.username like ? ";
			params.add("%" + username + "%");
		}
		if (realName != null && (realName = realName.trim()).length() > 0) {
			hql += "and a.realName like ? ";
			params.add("%" + realName + "%");
		}
		{
			hql += "order by a.registryDate desc ";
		}
		List<Account> accounts = getQueryChannel().queryResult(hql,
				params.toArray());
		for (Account a : accounts) {
			result.add(Convertor.po2vo(a, null));
		}
		return result;
	}

	/**
	 * 查出所有的accounts
	 * @param search
	 * @param page
	 * @param pageSize
	 * @return
	 */
	public List<AccountVO> listAcounts(AccountVO vo, int page, int pageSize) {
		int firstRow = (page - 1) * pageSize;
		List<Account> accounts = null;
		if (vo == null) {
			accounts = getQueryChannel().queryResult("from Account",
					new Object[] {}, firstRow, pageSize);
		} else {
			accounts = getQueryChannel()
					.queryResult(
							"from Account a where a.username like ? and a.realName like ?",
							new Object[] {
									vo.getUsername() == null ? "%" : vo
											.getUsername()
											+ "%",
									vo.getRealName() == null ? "%" : vo
											.getRealName()
											+ "%" }, firstRow, pageSize);
		}
		List<AccountVO> result = new ArrayList<AccountVO>();
		if (accounts == null) {
			return result;
		}
		for (Account a : accounts) {
			result.add(Convertor.po2vo(a, null));
		}
		return result;
	}

	public void setRoles(Long accountId, Long[] roleIds) {
		Account account = Account.get(accountId);
		if (account == null) {
			return;
		}
		if (account.getRoles() == null) {
			account.setRoles(new HashSet<Role>());
		}
		account.getRoles().clear();
		roleIds = roleIds == null ? new Long[0] : roleIds;
		for (Long roleId : roleIds) {
			Role r = Role.get(roleId);
			if (r != null) {
				account.getRoles().add(r);
			}
		}
		account.update();
	}

	public void addRole(Long accountId, Long[] roleIds) {
		Account account = Account.get(accountId);
		if (account == null || roleIds == null) {
			return;
		}
		if (account.getRoles() == null) {
			account.setRoles(new HashSet<Role>());
		}
		roleIds = roleIds == null ? new Long[0] : roleIds;
		for (Long roleId : roleIds) {
			Role r = Role.get(roleId);
			if (r != null && !account.getRoles().contains(r)) {
				account.getRoles().add(r);
			}
		}
		account.update();
	}

	public void removeRole(Long accountId, Long[] roleIds) {
		Account account = Account.get(accountId);
		if (account == null || roleIds == null || account.getRoles() == null
				|| account.getRoles().isEmpty()) {
			return;
		}
		roleIds = roleIds == null ? new Long[0] : roleIds;
		for (Long roleId : roleIds) {
			Role r = Role.get(roleId);
			if (r != null && account.getRoles().contains(r)) {
				account.getRoles().remove(r);
			}
		}
		account.update();
	}

	public List<RoleVO> findAccountRoles(Long accountId) {
		Account a = Account.get(accountId);
		if (a == null) {
			return new ArrayList<RoleVO>();
		}
		return (List<RoleVO>) Convertor.po2vo(a.findRoles(), new ArrayList(),
				null);
	}

	private AccountVO toAccountVO(Account account) {
		return Convertor.po2vo(account, null);
	}
}
